﻿#region Using References

using System;
using System.Diagnostics.CodeAnalysis;
using Beaker.OpenCube.Specs.NbtEditor.ViewModels.Builders;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace Beaker.OpenCube.Specs.NbtEditor.ViewModels
{
	[ExcludeFromCodeCoverage]
	[TestClass]
	public class ViewModelSpecs
	{
		#region Specs for SetAndRaiseIfChanged

		[TestMethod]
		public void UpdingPropertyWithNoHandlerShouldNotThrow()
		{
			// arrange
			ViewModelTester viewModel = new ViewModelBuilder()
				.Build();

			// act
			Action act = () => viewModel.Value = "FooBar";

			// assert
			act.ShouldNotThrow();
		}

		[TestMethod]
		public void UpdatingPropertyWithNewValueCallsOnValueChangedHandler()
		{
			// arrange
			bool isCalled = false;
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithOnValueChangedHandler( ( o, n ) => isCalled = true )
				.Build();


			// act
			viewModel.Value = "FooBar";

			// assert
			isCalled.Should().BeTrue();
		}

		[TestMethod]
		public void UpdatingPropertyWithSameValueDoesNotCallOnValueChangedHandler()
		{
			// arrange
			bool isCalled = false;
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithValue( "FooBar" )
				.WithOnValueChangedHandler( ( o, n ) => isCalled = true )
				.Build();

			// act
			viewModel.Value = "FooBar";

			// assert
			isCalled.Should().BeFalse();
		}

		[TestMethod]
		public void UpdatingPropertyWithNewValueCallsOnValueChangedHandlerWithCorrectArguments()
		{
			// arrange
			string oldValue = null;
			string newValue = null;
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithValue( "Old" )
				.WithOnValueChangedHandler( ( o, n ) => { oldValue = o; newValue = n; } )
				.Build();

			// act
			viewModel.Value = "New";

			// assert
			oldValue.Should().Be( "Old" );
			newValue.Should().Be( "New" );
		}

		[TestMethod]
		public void AfterUpdatingPropertyTheValueShouldHaveChanged()
		{
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithValue( "Old" )
				.Build();

			// act
			viewModel.Value = "New";

			// assert
			viewModel.Value.Should().Be( "New" );
		}

		[TestMethod]
		public void UpdatingPropertyRaisesThePropertyChangingBeforeValueChanges()
		{
			string observedValue = null;
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithValue( "Old" )
				.Build();
			viewModel.PropertyChanging += ( sender, args ) => { observedValue = viewModel.Value; };

			// act
			viewModel.Value = "New";

			// assert
			observedValue.Should().Be( "Old" );
		}

		[TestMethod]
		public void UpdatingPropertyRaisesThePropertyChangedAfterValuedHasChanged()
		{
			string observedValue = null;
			ViewModelTester viewModel = new ViewModelBuilder()
				.WithValue( "Old" )
				.Build();
			viewModel.PropertyChanged += ( sender, args ) => { observedValue = viewModel.Value; };

			// act
			viewModel.Value = "New";

			// assert
			observedValue.Should().Be( "New" );
		}

		#endregion
	}
}
